package cn.jd.basic.service.impl;

import cn.jd.basic.config.BussinessException;
import cn.jd.basic.constant.BaseConstants;
import cn.jd.basic.dto.*;
import cn.jd.basic.service.VerifyCodeService;
import cn.jd.basic.util.MD5Utils;
import cn.jd.basic.util.SendSmsUtils;
import cn.jd.basic.util.StrUtils;
import cn.jd.basic.util.VerifyCodeUtils;
import cn.jd.user.domain.Logininfo;
import cn.jd.user.domain.User;
import cn.jd.user.mapper.LogininfoMapper;
import cn.jd.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.SplitMapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.lang.model.util.ElementScanner6;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.sql.SQLOutput;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements VerifyCodeService {
    @Autowired
    private JavaMailSender sender;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LogininfoMapper logininfoMapper;

   /* @Autowired
    private VerifyCodeUtils verifyCodeUtils;*/

    /**
    * 手机验证码登录
    */
    @Override
    public void accountuser(AccountUserDto dto) {
        String imageCode= (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        if(!dto.getImageCodeValue().equals(imageCode)){
            throw new BussinessException("图片验证码错误,请重新输入！！！");
        }

        Logininfo user =logininfoMapper.loadByTypeOrUsername(dto.getUsername(),dto.getType());
        if(!checkTel(dto.getUsername())){
            throw new BussinessException("手机格式不正确，请重新输入手机号");
        }
        if(user==null){
            throw new BussinessException("用户不存在请重新输入");
        }
        // 判断两次短信验证码时间是否在60s间
        // 获取redis中的value
        String redisSmsCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getUsername()));
        String smsCode ="";
        if(!StringUtils.isEmpty(redisSmsCode)){
            // 获取key的剩余时间
            Long time = redisTemplate.getExpire(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getUsername()), TimeUnit.MINUTES);
            if(time>=4){
                throw new BussinessException("请勿频繁发送验证码");
            }
        }else {
            // 生成验证码
            smsCode= StrUtils.getRandomString(4);
        }
        // 验证码存到redis中的value
        String redisValue=smsCode+":"+ System.currentTimeMillis();
        log.info("验证码为：{}",smsCode);
        // 将数据存入到redis中
        redisTemplate.opsForValue().set(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE,dto.getUsername()),
                redisValue,1,TimeUnit.MINUTES);
        System.out.println(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE+"---"+dto.getUsername());
        System.out.println(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE,dto.getUsername()));
    }
    /**
     * 添加邮箱注册数据
     * @param
     */
    @Override
    public void registermail(RegisterMailDto dto) {
    // 判断两次邮箱是否相同
        String redisSmsCode = (String) redisTemplate.opsForValue().get(
                String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getEmail()));
        System.out.println(redisSmsCode+"pp");
        emailif(dto, redisSmsCode);
        // 添加日志
        Logininfo logininfo = new Logininfo();
        logininfo.setUsername(dto.getEmail());
        logininfo.setEmail(dto.getEmail());
        // 生成盐值
        String randomString = StrUtils.getRandomString(32);
        logininfo.setSalt(randomString);
        // 加密加岩
        String s = MD5Utils.encrypByMd5(randomString + dto.getMailpassword());
        logininfo.setPassword(s);
        // 设置值
        logininfoMapper.save(logininfo);
        System.out.println(logininfo.getId()+"id");
        // 添加用户
        User user1 = new User();
        user1.setCreatetime(new Date());
        user1.setEmail(dto.getEmail());
        user1.setUsername(dto.getEmail());
        user1.setLogininfoId(logininfo.getId());
        user1.setPassword(s);
        user1.setSalt(randomString);
        userMapper.save(user1);
    }

    private void emailif(RegisterMailDto dto, String redisSmsCode) {
        if (StringUtils.isBlank(redisSmsCode)) {

            throw new BussinessException("前后手机号请保持一致");
        }
        String[] smsCode = redisSmsCode.split(":");
        if (!smsCode[0].equals( dto.getMailsmsCode())) {

            throw new BussinessException("验证码错误！");
        }
        if (!dto.getMailpassword().equals(dto.getMailpasswordRepeat())) {
            throw new BussinessException("两次密码请保持一致");
        }
        // 是否注册过s
        User user = userMapper.findByPhone(dto.getEmail());
        if (null != user) {
            throw new BussinessException("该用户已被注册，请登录");
        }
    }


    /**
     * 获取邮箱验证码
     * @param dto
     */
    @Override
    public void mailsmsCode(MailDto dto) {
        // 判断验证码是否正确
        String value =(String)redisTemplate.opsForValue().get(dto.getMailimageCodeKey());
        if(!value.equals(dto.getMailimageCodeValue())){
            throw new BussinessException("验证码错误，请重新输入");
        }
        // 邮箱校验
        if(!checkEmaile(dto.getEmail())){
            throw new BussinessException("请输入正确的邮箱格式");
        }
        // 判断邮箱是否被注册过
        User user=userMapper.userByEmail(dto.getEmail());
        if(user!=null){
            throw new BussinessException("该邮箱已被注册，请登录！！");
        }
        // 判断两次短信验证码时间是否在60s间
        // 获取redis中的key
        String redisSmsCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getEmail()));
        String  mailsmsCode ="";
        if(!StringUtils.isEmpty(redisSmsCode)){
            // 获取key的剩余时间
            Long time = redisTemplate.getExpire(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getEmail()), TimeUnit.MINUTES);
            if(time>=4){
                throw new BussinessException("请勿频繁发送验证码");
            }
        }else {
            // 生成验证码
            mailsmsCode= StrUtils.getRandomString(4);
        }
        // 验证码存到redis中的value
        String redisValue= mailsmsCode+":"+ System.currentTimeMillis();
        log.info("验证码为：{}", mailsmsCode);
        // 将数据存入到redis中
        redisTemplate.opsForValue().set(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE,dto.getEmail()),
                redisValue,5,TimeUnit.MINUTES);


        // 发送邮件
        MimeMessage mimeMessage = sender.createMimeMessage();
        try {
            MimeMessageHelper helper  = new MimeMessageHelper(mimeMessage,true,"utf-8");
            helper.setFrom(dto.getEmail());
            helper.setSubject("注册验证码");
            // 3.设置文本内容，第二个参数 true 代表是否是一个html内容
            helper.setText("<h1>注册验证码</h1>"+
                    "注册验证码:"+mailsmsCode+"，该验证码5分钟内有效",true);
         /* // 4.添加附件
            helper.addAttachment("好东西.jpg",new File("C:\\Users\\lenovo\\Desktop\\1.jpg"));*/
            // 4.设置收件人
            helper.setTo(dto.getEmail());
        } catch (MessagingException e) {
            throw new BussinessException("发送邮件错误！");
        }
        // 6.发送邮件
        sender.send(mimeMessage);
    }



    @Override
    public String image(String key) {
        // 随机生成4为数
        String code = StrUtils.getRandomString(4);
        // 将数据存储到redis中
        redisTemplate.opsForValue().set(key,code,3, TimeUnit.MINUTES);
        // 生成base64并返回
        return VerifyCodeUtils.VerifyCode(100,40,code);
    }

    @Override
    public void registerPhone(RegisteredDto dto) {

        /*String redisSmsCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, getCodePhone.getPhone()));
        System.out.println(redisSmsCode+"55555");*/
        // 验证码是否正确 / 两次手机号是否一致
        String redisSmsCode = (String) redisTemplate.opsForValue().get(
                String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getPhone()));
        System.out.println(redisSmsCode+"pp");
        if (StringUtils.isBlank(redisSmsCode)) {

            throw new BussinessException("前后手机号请保持一致");
        }
        String[] smsCode = redisSmsCode.split(":");
        if (!smsCode[0].equals( dto.getSmsCode())) {

            throw new BussinessException("验证码错误！");
        }
        if (!dto.getPassword().equals(dto.getPasswordRepeat())) {
            throw new BussinessException("两次密码请保持一致");
        }
        // 是否注册过s
        User user = userMapper.findByPhone(dto.getPhone());
        if (null != user) {
            throw new BussinessException("该用户已被注册，请登录");
        }
        // 添加日志
        Logininfo logininfo = new Logininfo();
        logininfo.setUsername(dto.getPhone());
        logininfo.setPhone(dto.getPhone());
        // 生成盐值
        String randomString = StrUtils.getRandomString(32);
        logininfo.setSalt(randomString);
        // 加密加岩
        String s = MD5Utils.encrypByMd5(randomString + dto.getPassword());
        logininfo.setPassword(s);
        // 设置值
        logininfoMapper.save(logininfo);
        System.out.println(logininfo.getId()+"id");
        // 添加用户
        User user1 = new User();
        user1.setCreatetime(new Date());
        user1.setPhone(dto.getPhone());
        user1.setUsername(dto.getPhone());
        user1.setLogininfoId(logininfo.getId());
        user1.setPassword(s);
        user1.setSalt(randomString);
        userMapper.save(user1);

    }




    /**
     *  获取手机验证码
     */
    @Override
    public void smsCode(GetCodePhone getCodePhone) {
        if(getCodePhone.getType()!=null){
            if(!checkTel(getCodePhone.getPhone())){
                throw new BussinessException("手机格式不正确，请重新输入手机号");
            }
        }else {
            // 注册手机验证码判断
            loginphone(getCodePhone);
        }

        // 判断两次短信验证码时间是否在60s间
        // 获取redis中的value
        String redisSmsCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, getCodePhone.getPhone()));
       /* String smsCode ="";*/
        if(!StringUtils.isEmpty(redisSmsCode)){
            // 获取key的剩余时间
            Long time = redisTemplate.getExpire(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, getCodePhone.getPhone()), TimeUnit.MINUTES);
            if(time>=4){
                throw new BussinessException("请勿频繁发送验证码");
            }
        }
            // 生成验证码
         String  smsCode= StrUtils.getRandomString(4);

        // 验证码存到redis中的value
        String redisValue=smsCode+":"+ System.currentTimeMillis();
        log.info("验证码为：{}",smsCode);
        // 将数据存入到redis中
        redisTemplate.opsForValue().set(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE,getCodePhone.getPhone()),
                redisValue,5,TimeUnit.MINUTES);
        System.out.println(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE+"---"+getCodePhone.getPhone());
        // 发送短信
        /*  SendSmsUtils.sendSms(getCodePhone.getPhone(),"你宠物乐园的注册验证码:"+smsCode+"5分钟有效");*/
    }

    private void loginphone(GetCodePhone getCodePhone) {
        // 校验参数
        // 1.校验图形验证码是否正确
        // 1.1从redis中获取验证码
        if(getCodePhone.getImageCodeValue()==null){
            throw new BussinessException("图片验证码不能为空");
        }
        if(getCodePhone.getImageCodeKey()==null){
            throw new BussinessException("图片验证码key不能为空");
        }
        String imageCode= (String) redisTemplate.opsForValue().get(getCodePhone.getImageCodeKey());
        if(!imageCode.equalsIgnoreCase(getCodePhone.getImageCodeValue()) ){
            throw new BussinessException("图片验证码不正确");
        }
        //2.判断手机号码是否被注册过
        User user = userMapper.findByPhone(getCodePhone.getPhone());
        if(!checkTel(getCodePhone.getPhone())){
            throw new BussinessException("手机格式不正确，请重新输入手机号");
        }

        if(user!=null){
            throw new BussinessException("该用户已被注册，请登录");
        }
    }


    /*
     * 电话号码校验
     */
    private static Boolean checkTel(String tel) {

        //编译正则表达式
        String reg ="^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$" ;

        return tel.matches(reg)?true:false;
    }
    public static boolean checkEmaile(String emaile){
        String regex = "[1-9][0-9]{8,10}\\@[q][q]\\.[c][o][m]";
        //正则表达式的模式 编译正则表达式
        Pattern p = Pattern.compile(regex);
        //正则表达式的匹配器
        Matcher m = p.matcher(emaile);
        //进行正则匹配
        return m.matches();
    }

}
